<template>
  <div class="fx-drawer" :style="{zIndex}" :class="[direction,{'drawer-leave':drawerClose}]" v-if="currentVisible">
    <div class="fx-drawer-inner" :style="drawerStyle">
      <div class="fx-drawer-header" v-if="title!==''||$slots.title">
        <div class="fx-drawer-title">
          <slot name="title">{{ title }}</slot>
        </div>
        <div class="fx-drawer-close" @click.stop="drawerCloseClick('close')">
          <i class="iconfont icon-multiply fs12"/>
        </div>
      </div>
      <slot></slot>
    </div>
    <div class="fx-drawer-modal" :class="{'drawer-leave':drawerClose}"
         @click.stop="drawerCloseClick('modal')"></div>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, onBeforeUnmount, PropType, ref, watch } from 'vue'
import { useModelWatch, getZIndex } from '@/base/hooks'
import { codeRule } from '@/base/types'

export type DrawerBeforeClose = (cb: () => void) => void

interface DrawerProps {
  visible: boolean;
  title: string;
  direction: 'left' | 'right' | 'top' | 'bottom';
  width: string;
  closeOnModal: boolean;
  closeOnEscape: boolean;
  beforeClose: DrawerBeforeClose;
}

export default defineComponent({
  name: 'FDrawer',
  props: {
    visible: {
      type: Boolean as PropType<boolean>,
      required: true
    },
    title: {
      type: String as PropType<string>,
      default: ''
    },
    direction: {
      type: String as PropType<'left' | 'right' | 'top' | 'bottom'>,
      default: 'right'
    },
    width: {
      type: String as PropType<string>,
      default: '300'
    },
    closeOnModal: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    closeOnEscape: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    beforeClose: {
      type: Function as PropType<DrawerBeforeClose>,
      default: null
    }
  },
  setup (props: DrawerProps) {
    const zIndex = getZIndex()
    const currentVisible = ref<boolean>(props.visible)
    useModelWatch(() => props.visible, currentVisible, ['update:visible'])
    watch(currentVisible, (val: boolean) => {
      if (val) {
        document.addEventListener('keydown', handleEscClose, false)
      } else {
        document.removeEventListener('keydown', handleEscClose, false)
      }
    })
    const drawerClose = ref<boolean>(false)
    const closeDrawer = (): void => {
      drawerClose.value = true
      setTimeout(() => {
        currentVisible.value = false
        drawerClose.value = false
        document.removeEventListener('keydown', handleEscClose, false)
      }, 300)
    }
    const drawerCloseClick = (type: 'close' | 'modal' | 'esc'): void => {
      if (type === 'modal' && !props.closeOnModal) return
      if (type === 'esc' && !props.closeOnEscape) return
      if (props.beforeClose) {
        props.beforeClose(() => {
          closeDrawer()
        })
        return
      }
      closeDrawer()
    }
    const handleEscClose = (ev: KeyboardEvent): void => {
      if (ev.code === 'Escape') drawerCloseClick('esc')
    }

    const drawerStyle = computed(() => {
      const rel = codeRule.test(props.width)
      const path = props.direction === 'left' || props.direction === 'right' ? 'width' : 'height'
      const style: { [key: string]: string } = {}
      style[path] = rel ? props.width : `${props.width}px`
      return style
    })

    onBeforeUnmount(() => {
      document.removeEventListener('keydown', handleEscClose, false)
    })

    return {
      zIndex,
      drawerClose,
      drawerStyle,
      currentVisible,
      drawerCloseClick
    }
  }
})
</script>
